package com.tom.demo.common.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池工厂类
 * 负责创建和管理项目中的线程池
 * 该类采用spring管理的单例模式，在应用启动的时候初始化线程池，关闭时优雅释放资源
 *  主要特点:
 *  1:支持配置文件yaml中配置线程池参数
 *  2:提供线程池监控功能
 *  3:优雅的关闭机制，防止内存泄漏
 *  4:自定义拒绝策略和异常处理
 */
@Slf4j
@Configuration
public class ThreadPoolFactoryConfig implements DisposableBean {
    /**
     * 线程池执行器实例，用于提交异步任务。
     * 使用 ExecutorService 接口而非具体实现，保持抽象。
     */
    private ExecutorService executorService;

    /**
     * 核心线程数，默认为 CPU 核心数。
     * 核心线程会一直存活（除非 allowCoreThreadTimeOut=true）。
     */
    @Value("${thread.pool.core-size:#{T(java.lang.Runtime).getRuntime().availableProcessors()}}")
    private int corePoolSize;

    /**
     * 最大线程数，默认为 CPU 核心数 * 2。
     * 当队列满且线程数未达上限时，会创建新线程。
     */
    @Value("${thread.pool.max-size:#{T(java.lang.Runtime).getRuntime().availableProcessors() * 2}}")
    private int maxPoolSize;

    /**
     * 线程空闲超时时间（秒）。
     * 当线程数 > corePoolSize 时，空闲线程超过此时间将被回收。
     * 由于 allowCoreThreadTimeOut(true)，核心线程也会超时回收。
     */
    @Value("${thread.pool.keep-alive-time:60}")
    private long keepAliveTime;

    /**
     * 任务队列容量（有界队列）。
     * 使用有界队列可防止内存溢出，但需配合合理的拒绝策略。
     */
    @Value("${thread.pool.queue-capacity:200}")
    private int queueCapacity;

    /**
     * Spring 容器初始化完成后创建线程池。
     * 同时校验配置参数合法性，并记录初始化日志。
     */
    @PostConstruct
    public void init() {
        // 参数校验
        if (corePoolSize <= 0) {
            throw new IllegalArgumentException("corePoolSize must be > 0");
        }
        if (maxPoolSize < corePoolSize) {
            throw new IllegalArgumentException("maxPoolSize must be >= corePoolSize");
        }
        if (queueCapacity <= 0) {
            throw new IllegalArgumentException("queueCapacity must be > 0");
        }
        if (keepAliveTime < 0) {
            throw new IllegalArgumentException("keepAliveTime must be >= 0");
        }

        this.executorService = createExecutor();
        log.info("ThreadPoolFactory init success, corePoolSize={}, maxPoolSize={}, keepAliveTime={}, queueCapacity={}",
                corePoolSize, maxPoolSize, keepAliveTime, queueCapacity);
    }

    /**
     * 创建自定义线程池。
     * 关键设计：
     * - 有界队列防止 OOM
     * - 自定义线程工厂（命名、异常处理）
     * - 自定义拒绝策略（降级执行）
     * - 允许核心线程超时
     */
    private ExecutorService createExecutor() {
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueCapacity);

        ThreadFactory threadFactory = new ThreadFactory() {
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private static final String THREAD_NAME_PREFIX = "MyApp-ThreadPool-";

            @Override
            public Thread newThread(@NotNull Runnable r) {
                Thread thread = new Thread(r, THREAD_NAME_PREFIX + threadNumber.getAndIncrement());
                // 关键：不要设为守护线程！否则 JVM 退出时任务会丢失
                thread.setDaemon(false);
                thread.setPriority(Thread.NORM_PRIORITY);
                //为当前线程设置一个未捕获异常的处理器（Uncaught Exception Handler），用于捕获并处理该线程中未被 try-catch 捕获的异常。
                thread.setUncaughtExceptionHandler((t, ex) -> log.error("Uncaught exception in thread: {}, message: {}", t.getName(), ex.getMessage(), ex));
                return thread;
            }
        };

        return getThreadPoolExecutor(workQueue, threadFactory);
    }

    /**
     * 构建 ThreadPoolExecutor 实例。
     *
     * @param workQueue      任务队列（有界）
     * @param threadFactory  线程工厂
     * @return 配置完成的线程池
     */
    @NotNull
    private ThreadPoolExecutor getThreadPoolExecutor(
            BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory) {
        //拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = (runnable, executor) -> {
            log.warn("Task rejected - queue full. QueueSize: {}, ActiveThreads: {}",
                    executor.getQueue().size(), executor.getActiveCount());

            // 降级策略：在调用者线程中执行任务（注意：会阻塞调用者！）
            if (!executor.isShutdown()) {
                runnable.run();
            }
        };

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                workQueue,
                threadFactory,
                rejectedExecutionHandler
        );

        // 允许核心线程在空闲时超时回收，节省资源
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        return threadPoolExecutor;
    }

    /**
     * Spring 容器销毁时优雅关闭线程池。
     * 防止资源泄漏和 JVM 无法退出。
     */
    @Override
    public void destroy() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                    if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                        log.warn("ThreadPool did not terminate gracefully after shutdownNow()");
                    }
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
                log.warn("Interrupted during thread pool shutdown", e);
            }
        }
    }

    @Bean("executorService")
    public ExecutorService executorService() {
        // 确保 init() 已经执行；Spring 会在创建 bean 时调用 @PostConstruct
        return this.executorService;
    }
}
